#include "config_boot.h"
#include "cJSON.h"
#include "json_to_data.h"
#include "uc_log.h"
#include <fal.h>
#include <rtdevice.h>
#include <rtthread.h>
#include <string.h>
#include <unistd.h>

int parse_uboot_cfg(const cJSON *data_json, uboot_cfg_t *uboot_cfg)
{
    const cJSON *uboot_cfg_obj = cJSON_GetObjectItemCaseSensitive(data_json, UBOOT_CFG);
    if (!uboot_cfg_obj)
    {
        return -1;
    }

    parse_string(uboot_cfg_obj, UMODEM_UART, uboot_cfg->ymode_uart, sizeof(uboot_cfg->ymode_uart));
    parse_uint8(uboot_cfg_obj, YM_WAIT_TIME, &uboot_cfg->ymode_wait_time);
    parse_uint8(uboot_cfg_obj, UBOOT_MODE, &uboot_cfg->uboot_mode);
    parse_uint8(uboot_cfg_obj, OTA_STATE, &uboot_cfg->ota_state);
    parse_uint32(uboot_cfg_obj, OTA_SIZE, &uboot_cfg->ota_size);

    return 0;
}

int add_uboot_cfg(cJSON *data_json, const uboot_cfg_t *uboot_cfg)
{
    cJSON *uboot_cfg_obj = cJSON_CreateObject();
    if (!uboot_cfg_obj)
    {
        return 1;
    }

    cJSON_AddStringToObject(uboot_cfg_obj, UMODEM_UART, uboot_cfg->ymode_uart);
    cJSON_AddNumberToObject(uboot_cfg_obj, YM_WAIT_TIME, uboot_cfg->ymode_wait_time);
    cJSON_AddNumberToObject(uboot_cfg_obj, UBOOT_MODE, uboot_cfg->uboot_mode);
    cJSON_AddNumberToObject(uboot_cfg_obj, OTA_STATE, uboot_cfg->ota_state);
    cJSON_AddNumberToObject(uboot_cfg_obj, OTA_SIZE, uboot_cfg->ota_size);

    cJSON_AddItemToObject(data_json, UBOOT_CFG, uboot_cfg_obj);

    return 0;
}

// 读boot分区的最后4K，最为BOOT存储参数
int read_boot_param(char *buf)
{
    int length;
    const struct fal_partition *app_part;
    app_part = fal_partition_find(BOOT_PARAMENT_NAME);
    if (app_part == NULL)
    {
        TRACE_E("boot partition not find");
        return 1;
    }
    length = fal_partition_read(app_part, app_part->len - BOOT_PARAMENT_SIZE, buf, BOOT_PARAMENT_SIZE);
    if (length <= 0)
    {
        TRACE_E("boot partition read err.");
        return 2;
    }

    return 0;
}

int write_boot_param(char *buf, int len)
{
    int result;
    rt_base_t level;
    const struct fal_partition *app_part;

    app_part = fal_partition_find(BOOT_PARAMENT_NAME);
    if (app_part == NULL)
    {
        TRACE_E("boot partition not find.");
        return 1;
    }

    level = rt_hw_interrupt_disable();
    fal_partition_erase(app_part, app_part->len - BOOT_PARAMENT_SIZE, BOOT_PARAMENT_SIZE);
    rt_hw_interrupt_enable(level);

    level = rt_hw_interrupt_disable();
    result = fal_partition_write(app_part, app_part->len - BOOT_PARAMENT_SIZE, buf, len > BOOT_PARAMENT_SIZE ? BOOT_PARAMENT_SIZE : len);
    rt_hw_interrupt_enable(level);

    return result;
}

int get_boot_param(uboot_cfg_t *boot_parament)
{
    int result;
    char *buf;
    cJSON *root_json = NULL, *data_json = NULL;

    buf = rt_malloc(BOOT_PARAMENT_SIZE);
    if (buf == RT_NULL)
    {
        TRACE_E("malloc boot param buf fail");
        return 1;
    }
    result = read_boot_param(buf);
    if (result != 0)
    {
        TRACE_E("read boot param fail");
        goto cjson_err;
    }

    /* 检验配置文件完整性 */
    root_json = cJSON_Parse(buf);
    if (!root_json)
    {
        result = 2;
        TRACE_E("get root_json fail");
        goto cjson_err;
    }

    if (0 != parse_uboot_cfg(root_json, boot_parament))
    {
        result = 3;
        goto boot_end;
    }

    result = 0;
boot_end:
    cJSON_Delete(root_json);
cjson_err:
    rt_free(buf);
    return result;
}

int set_boot_param(uboot_cfg_t *boot_parament)
{
    char *data = NULL;
    cJSON *root_json = cJSON_CreateObject();
    int result = 0;

    if (!root_json)
    {
        result = 1;
        goto end;
    }

    add_uboot_cfg(root_json, boot_parament);

    data = cJSON_Print(root_json);
	if (RT_NULL != data)
	{
		result = write_boot_param(data, rt_strlen(data));
		rt_free(data);
	}
end:
    cJSON_Delete(root_json);
    return result;
}